home *** CD-ROM | disk | FTP | other *** search
/ TPUG - Toronto PET Users Group / TPUG Users Group CD / TPUG Users Group CD.iso / AMIGA / AMICUS / AMIBEST2.ADF / Best of AMICUS 2 / Txt / txt.c < prev    next >
C/C++ Source or Header  |  1987-07-22  |  13KB  |  518 lines

  1. /***************************************************************************/
  2. /* txt   Reformat to TEXT: cr to lf, tabs, wordwrap, strip 0x80, ctrl chrs */
  3. /*        Copyright (c) 1986, 1987 by Ray Lance               */
  4. /* Released to the public domain, freely redistributable "shareware", but  */
  5. /* distribution must be of this entire txt.arc file.     8/24/86 v.1 13:10 */
  6. /***************************************************************************/
  7. /* 0x08 = backspace handling            added    10/03/86     13:30 */
  8. /* Re[-p]aragraphing wordwrap option        added    12/22/86 v.2 17:20 */
  9. /* Don't re-paragraph item [-h]eaders option    added    12/25/86     22:15 */
  10. /* Aztec-ized (removed unsigned char dependency)    12/26/86     04:45 */
  11. /* Don't remove extra [-f]ormfeeds option    added    12/27/86     18:40 */
  12. /* Insert [-r]eturn in output line-endings    added    12/27/86     19:30 */
  13. /* Options listing if ? or no paramaters    added    12/27/86     20:15 */
  14. /* Don't [-b]ackspace made optional        added    12/27/86     21:45 */
  15. /* Turn [-s]paces into tabs            added    12/28/86     03:30 */
  16. /* Output to TMP (MSDOS) + outfile msg        added    12/31/86     08:20 */
  17. /* Default MSDOS line ending is cr/lf        added     1/01/87     14:00 */
  18. /* Remove [-d]oublespacing            added     1/02/87     20:10 */
  19. /* Don't EOF on ^Z (-z)                added     1/05/87     22:00 */
  20. /***************************************************************************/
  21.  
  22. #include <stdio.h>
  23. #include <ctype.h>
  24.  
  25. #ifdef M68000        /* Lattice? */
  26. /* #define L303 1    /* NOTE: must be defined for ver 3.03 */
  27. #ifdef L303
  28. extern Enable_Abort;    /* ^C handling */
  29. #endif
  30. int strlen(char *);
  31. char *strchr(char *, int);
  32. char *strcpy(char *, char *);
  33. char *strcat(char *, char *);
  34. #else
  35. #include <string.h>
  36. #endif
  37.  
  38. #ifdef M_I86        /* MSC 4.00 options? */
  39. #include <stdlib.h>
  40. #define local static    /* locally defined for MS CodeView debugger */
  41. char rd[] = "rb";    /* & O_BINARY, 'cause default is translate */
  42. char wr[] = "wb";
  43. #else
  44.         /* NO, set for Lattice and Manx Aztec: */
  45. #define local        /* globally defined for Amiga MetaScope debugger */
  46. char rd[] = "r";    /* & others default to no translate. */
  47. char wr[] = "w";
  48. #ifdef MPU68000
  49. #define AMIGA 1
  50. #endif
  51. #endif
  52.  
  53. #ifdef MSDOS
  54. #define dirchar '\\'
  55. #else
  56. #define dirchar '/'
  57. #endif
  58.  
  59. #ifdef AMIGA        /* Aztec & Lattice 3.03 have non-Unix: */
  60. #define memset(d, c, n) setmem(d, n, c)
  61. #define memcpy(d, s, n) movmem(s, d, n)
  62. #endif            /* (while Lattice 3.10 has both versions) */
  63.  
  64. #ifndef min
  65. #define min(a,b) ((a) < (b) ? (a) : (b))
  66. #define max(a,b) ((a) > (b) ? (a) : (b))
  67. #endif
  68.  
  69. char *strvchr();
  70.  
  71.  
  72. local FILE *in, *out;
  73. local char filename[64] = "ram:";
  74. local struct {
  75.     char nul;       /* null stopper for backward search of */
  76.     char lin[256];        /* the OUTPUT LINE */
  77.     char stp;       /* extra for forced chopping */
  78. } inp, outp;
  79. #define line outp.lin
  80.  
  81. local char  opt[] = "ctbdfrwhpxsz"; /* Command Line options: if specified, */
  82. local char kopt[] = "ctbdfrwhpxsz";
  83.  
  84. #define ctl 0    /* control chars ( < 0x20 ): 0=discard, else + 0x80
  85.             except tab, which is treated separately: */
  86. #define tab 1    /* tab columns per tab: 0 = 8 */
  87. #define bsp 2    /* don't backspace */
  88. #define dbl 3    /* delete doublespacing */
  89. #define frm 4    /* don't remove extra formfeeds */
  90. #define ret 5    /* insert return in output line-endings */
  91. #define wrp 6    /* word wrap: 0 or no col # = 77 -- default 255 */
  92. #define hdr 7    /* don't hard-paragraph item headers */
  93. #define par 8    /* re-paragraph word wrap */
  94. #define x80 9    /* don't strip 80 bits */
  95. #define spc 10    /* turn multiple spaces into tabs every n columns */
  96. #define end 11    /* don't EOF on ^Z */
  97.  
  98. char *optlist[] = {
  99. "  USAGE: TXT [options] input_filename [options] [output_filename] [options]",
  100. #ifndef MSDOS
  101. "        OUTPUT will go to RAM:input_filename if not specified",
  102. #else
  103. "        OUTPUT will go to TMP\\input_filename if not specified",
  104. #endif
  105. " ",
  106. "      The following options must be lowercase and preceded by a hyphen each:",
  107. "  Where:   ([n] = 0 if omitted)",
  108. "    -b    don't delete prev char on backspace, leave bsp to -c option",
  109. "    -c[n]    n=0: discard control chars (chars < 0x20); n>0: char + 0x80",
  110. "    -d    un-doublespace (remove every other extra line ending)",
  111. "    -f    don't remove extra formfeeds, leave them to the -c option",
  112. "    -h    don't preserve format of item headers (text surrounded by",
  113. "         lines of at least 4 same characters, like \"----\"), but...",
  114. "    -p    invoke re-paragraphing: i.e., the changing of line-endings to",
  115. "         spaces except when the 1st char of the next line isspace()",
  116. #ifndef MSDOS
  117. "    -r[n]    n=0: cr 'sted linefeed at endline; n>0: output both cr & lf",
  118. #else
  119. "    -r[n]    n=0: delete return from endline cr/lf; n>0: delete linefeed",
  120. #endif
  121. "    -s[n]    change multiple spaces into tabs to every n columns (0 = 8)",
  122. "    -t[n]    change tabs into spaces to every n columns (0 = 8)",
  123. "    -w[n]    wordwrap at n chars/line (n can be up to 254; 0 = 77)",
  124. "    -z    don't end file on ^Z, let -c option handle the character",
  125. "    -x    don't strip 0x80 bits before any of the above",
  126. " ",
  127. " You may enter option(s) now; then you will be asked for input filename:",
  128. #ifndef MSDOS
  129. "     (or ^C to abort)                (output to RAM:)",
  130. #else
  131. "     (or ^C to abort)                (output to TMP\\)",
  132. #endif
  133. ""};
  134.  
  135. local int s = 0;    /* cols in source line image */
  136. local int m = 0;    /* cols in output line image */
  137. local int spaces = 0;    /* spaces converted from tab, yet to output */
  138. local int tabin, tabout;    /* # cols in input & output tabs */
  139.  
  140. local char *g;        /* where to get from */
  141. local char *w;        /* end of get buffer */
  142.  
  143.  
  144. main(argc,argv)
  145. int argc;
  146. char *argv[];
  147. {
  148. register char *p = line;     /* assembling line */
  149. register int c = 0, l = 0;    /* char, last char */
  150. int dsp = 0;    /* kill next endline (doublespacing) */
  151. int ff = 0;    /* last char formfeed or not space */
  152. int i = 0;    /* count of identical non-data chars at begin line */
  153. int j = 0;    /* count of chars in incoming line */
  154. int k = 0;    /* identity of identical char */
  155. int n = 0;    /* general work storage */
  156. int z = 0;    /* # spaces to replace tab with */
  157. char *endlin, pgh, pgf, *force(), *newline(), *rm_end_spc(); /* wordwrap */
  158. char **o, *f;    /* options display &c. */
  159. char *b;    /* backwards looking for space-to-tab output */
  160.  
  161. #ifdef L303
  162. Enable_Abort = 1;    /* Lattice ^C handling */
  163. #endif
  164.  
  165. getopt(&argc, argv, opt);     /* GET COMMAND LINE OPTIONS */
  166.  
  167. if (argc < 2  ||  *argv[1] == '?')
  168.     {
  169.     for (o = optlist; **o; fprintf(stderr, "%s\n", *o), o++);
  170.     gets(f = line);
  171.     while (*f == ' ')
  172.         strcpy(f, f+1);
  173.     if (strlen(line))
  174.         {
  175.         argc = 2;
  176.         argv[1] = line;
  177.         strcpy(opt, kopt);
  178.         getopt(&argc, argv, opt);
  179.         }
  180.     }
  181.  
  182. if (opt[tab] == 0)
  183.     opt[tab] = 8;        /* tab defaults to 8 spaces */
  184. else if (++opt[tab])
  185.     opt[tab]--;
  186.  
  187. if (opt[spc] == 0)
  188.     opt[spc] = 8;        /* as does spaces-to-tabs */
  189. else if (++opt[spc])
  190.     opt[spc]--;
  191.  
  192. if ((tabin = opt[tab]) == 0)
  193.     tabin = 8;
  194. if ((tabout = opt[spc]) == 0)
  195.     tabout = tabin;
  196.  
  197. if (opt[wrp] == 0)
  198.     opt[wrp] = 77;      /* & word wrap after col 77 */
  199. if (opt[x80]--)
  200.     opt[x80] = 127;         /* strip 80 can only do that (or not) */
  201. if (opt[par] != -1)
  202.     opt[par] = 0;        /* re-paragraphing active = 0 */
  203. pgf = pgh = opt[par];
  204. opt[hdr]++;         /* hard-headers active = 0 */
  205. opt[bsp]++;
  206. opt[dbl]++;
  207. opt[frm]++;
  208. #ifdef MSDOS
  209. if (opt[ret] > 0)
  210.     opt[ret] = 1;
  211. #else
  212. opt[ret]++;
  213. #endif
  214. if (opt[ret] > 0  &&  opt[wrp] == -1)
  215.     opt[wrp]--;
  216. endlin = line + opt[wrp];
  217. memset(line, 0, sizeof(line));
  218.  
  219.  
  220. while (!(in = fopen(argv[1], rd)))     /* OPEN INPUT FILE */
  221.        {
  222.        fprintf(stderr, "Can't open input %s! New file name: ", argv[1]);
  223.        gets(argv[1] = line);
  224.        }
  225. if (argc < 3)
  226.     {
  227. #ifdef MSDOS
  228.     if ((f = getenv("TMP"))  ||  (f = getenv("ARCTEMP")) ) {
  229.         strcpy(filename, f);
  230.         strcat(filename, "\\");
  231.         }
  232. #endif
  233.     if (!(f = strvchr(argv[1] + strlen(argv[1]) - 1, dirchar)))
  234.         if (!(f = strchr(argv[1], ':')))
  235.             f = argv[1] - 1;
  236.     argv[2] = strcat(filename, ++f);    /* DEFAULT OUTPUT TO RAM: */
  237.     }
  238. while (!(out = fopen(argv[2], wr)))     /* OPEN OUTPUT FILE */
  239.        {
  240.        fprintf(stderr, "Can't open output %s! New file name: ",argv[2]);
  241.        gets(argv[2] = filename);
  242.        }
  243.  
  244. while ((c = get()) != EOF)
  245.         {
  246.         switch (c &= opt[x80])
  247.             {
  248.             case 26:       /* MSDOS EOF  (^Z) */
  249.                 if (opt[end] != EOF)
  250.                     goto other;
  251.                 unget(EOF);
  252.                 break;
  253.  
  254.  
  255.             case '\r':        /* <RETURN> */
  256.  
  257.                 if (((c = get()) & opt[x80]) != '\n')
  258.                     unget(c);
  259.  
  260.  
  261.             case '\n':        /* LF */
  262.  
  263.                 j = -1;
  264.                 c = unget(get()) & opt[x80];
  265.  
  266.                     /* discard doublespacing... */
  267.  
  268.                 if (opt[dbl]  &&  ( dsp =
  269.                   (!dsp & (c == '\n' | c == '\r'))))
  270.                     break;
  271.  
  272.                 p = rm_end_spc(p); /* kill trailing spaces */
  273.                 s = spaces = 0;
  274.                 if (!opt[hdr]) /* if hard-hdrs not killed, */
  275.                   if (i > 3) {  /* and line is 4 or more */
  276.                     if (k == l) /* identical chars, */
  277.                         { k = 0; pgh=opt[par]; }
  278.                     else {    /* let it flip-flop */
  279.                         if (m > i) {
  280.                             unget('\n');
  281.                             p = force(p);
  282.                             break;
  283.                             }
  284.                         k = l; /* re-paragraphing. */
  285.                         pgf = pgh = 1;
  286.                         }
  287.                     }
  288.  
  289.                 /* newline goes out as either nl or space: */
  290.  
  291.                 if (isspace(c)  ||  pgf  ||  (p <= line))
  292.                         p = newline(p);
  293.                 else {unget(' '); j--;}
  294.                 pgf = pgh;
  295.                 break;
  296.  
  297.  
  298.             case '\b':        /* BACKSPACE */
  299.                 if (opt[bsp])
  300.                     goto other;
  301.                 if (m) {
  302.                     p--;
  303.                     m--;
  304.                     s--;
  305.                     }
  306.                 break;
  307.  
  308.  
  309.             case '\f':        /* FORMFEED */
  310.                 if (opt[frm]  ||  c != ff)
  311.                     goto other;
  312.                 break;
  313.  
  314.  
  315.             case '\t':        /* TAB */
  316.                 z = tabin - (s % tabin) - 1;
  317.                 if (opt[tab]) {
  318.                     spaces += z;
  319.                     c = ' ';
  320.                     }
  321.                 else    {
  322.                     s += z;
  323.                     m += tabout - (m % tabout) - 1;
  324.                     }
  325.  
  326.             default:
  327. other:                if (c < ' '  &&  c != '\t')
  328.                    if (opt[ctl] == 0)     /* discard ctrls? */
  329.                     break;
  330.                    else if (opt[ctl] != -1)
  331.                     c |= 128;    /* no, shift hi */
  332.  
  333.                 *p++ = c;    /* STORE CHAR IN LINE */
  334.  
  335.                 if (c != '\f') {
  336.                     m++;
  337.                     s++;
  338.                     }
  339.  
  340.                 if (opt[spc]  &&  !(m % tabout))
  341.                     {
  342.                     for (b = p; *--b == ' ';);
  343.                     if ((z = p - ++b) > 1)
  344.                         {
  345.                         p = b;
  346.                         n = z % tabout != 0;
  347.                         z = tabout * (z/tabout+n);
  348.                         m -= z;
  349.                         s -= z;
  350.                         spaces += z;
  351.                         }
  352.                     while (spaces >= tabout)
  353.                         {
  354.                         *p++ = '\t';
  355.                         m += tabout;
  356.                         s += tabout;
  357.                         spaces -= tabout;
  358.                         }
  359.                     }
  360.                 if (m >= (unsigned char)opt[wrp])
  361.                     p = force(p);    /* if past end */
  362.                 break;
  363.             }
  364.     if (i == j  &&  (i == 0  ||  c == l)
  365.               &&   c > ' '  &&  !isalnum(c) )
  366.  
  367.         i++; /* count: identical non-data chars at begin line */
  368.     else i = 0;
  369.  
  370.     if (c == '\f'  ||  !isspace(c))
  371.         ff = c;
  372.     l = c;
  373.     j++;
  374.     }
  375. if (p > line)
  376.     newline(p);
  377. fprintf(stderr, "Input was %ld bytes\n", ftell(in));
  378. fprintf(stderr, "Output is %ld bytes in \"%s\".\n", ftell(out), argv[2]);
  379. return(exit(0));
  380. }
  381.  
  382.  
  383. char *force(p)           /* wrap at any space or punctuation */
  384. char *p;
  385. {
  386. register char *g, *w;
  387.  
  388. w = g = p;
  389. if (opt[wrp] != -1) {
  390.   for (; --g >= line  &&  !isspace(*g);); /* find first space, */
  391.   if (p - g > 10  ||  g < line) {
  392.     while (--p >= line  &&  !ispunct(*p));  /* and punctuation; */
  393.     if (p > g  ||  g < line)
  394.         g = p;            /* pick punctuation if spc <-- 10 */
  395.     if (g < line)
  396.         g = w - 1;    /* or force the bloody thing if neither. */
  397.     }
  398.   for (++g; --w >= g; unget(*w));        /* save chars, */
  399.   newline(g);            /* make new line, */
  400.   } else fwrite(line, p - line, 1, out);
  401. return(line);        /* & return ptr. */
  402. }
  403.  
  404.  
  405. char *newline(p)    /* put newline: */
  406. char *p;
  407. {
  408. p = rm_end_spc(p);    /* delete trailing spaces */
  409. if (opt[ret])
  410.     *p++ = '\r';
  411. if (opt[ret] != 1)
  412.     *p++ = '\n';
  413. fwrite(line, p - line, 1, out);
  414. m = 0;            /* no cols in line now */
  415. return(line);
  416. }
  417.  
  418.  
  419. char *rm_end_spc(p)         /* remove redundant end (trailing) spaces */
  420. char *p;
  421. {
  422. register int n = 0;
  423. for (; --p >= line  &&  isspace(*p);) {
  424.     switch(*p)
  425.         {
  426.         case ' ':
  427.             spaces++;
  428.             break;
  429.  
  430.         case '\t':
  431.             spaces += tabout;
  432.             break;
  433.  
  434.         case '\f':
  435.             n++;
  436.  
  437.         default:
  438.             break;
  439.         }
  440.     }
  441. if (spaces < 3  ||  p < line)
  442.     spaces = 0;
  443. for (; n--; *++p = '\f');    /* replace formfeeds */
  444. return(++p);
  445. }
  446.  
  447.  
  448.  
  449. getopt(argc, argv, opt)       /* GET COMMAND LINE OPTIONS */
  450. int *argc;
  451. char **argv;
  452. char *opt;
  453. {
  454. register int i, n, r = 0, nopt = strlen(opt);
  455. char options[80], *o = options;
  456.  
  457. for (*o = 0, i = *argc; i--;) /* collect all the options first: */
  458.     {
  459.     if (**argv == '-')  /* if this arg is an option, */
  460.         {
  461.         strcat(o, *argv);     /* collect it, */
  462.         if (i)
  463.           memcpy((char *)&argv[0], (char *)&argv[1], i*sizeof(argv));
  464.         --*argc;  /* and delete this arg. */
  465.         }
  466.     else argv++;
  467.     }
  468.  
  469. while (nopt--)      /* for each option permitted: */
  470.     {
  471.     for (n = -1, o = options; *o;)     /* for each option collected: */
  472.         if (o = strchr(o, '-'))
  473.            if (*++o == *opt)           /* if option, */
  474.             {
  475.             n = atoi(++o); /* subst # given ( or 0) */
  476.             r++;
  477.             break;
  478.             }
  479.     *opt++ = n;    /* else (option not present), kill option (-1). */
  480.     }
  481. return(r);     /* return # options actually present. */
  482. }
  483.  
  484.  
  485. char *strvchr(s, c)     /* Search char from RHE of string */
  486. register char *s;
  487. register int c;
  488. {
  489. while (*s != c)     /* ck for match 1st, in case it's NUL we're looking for */
  490.     if (*s-- == 0)
  491.         return(NULL);  /* end string: return not found */
  492. return(s);         /* FOUND char: return location. */
  493. }
  494.  
  495.  
  496.  
  497. get()        /* GET NEXT CHARACTER */
  498. {
  499. register int c;
  500. if (g < w)
  501.     c = *g++;
  502. else if (spaces) {
  503.     spaces--;
  504.     c = ' ';
  505.     }
  506. else c = fgetc(in);
  507. return(c);
  508. }
  509.  
  510.  
  511. unget(c)    /* UNGET CHARACTER */
  512. char c;
  513. {
  514. if (g >= w)
  515.     g = w = &inp.stp;
  516. return(int)(*--g = c);
  517. }
  518.